package cn.minhx.domain.strategy.service.rule.chain.impl;

import cn.minhx.domain.strategy.repository.IStrategyRepository;
import cn.minhx.domain.strategy.service.armory.IStrategyDispatch;
import cn.minhx.domain.strategy.service.rule.chain.AbstractLogicChain;
import cn.minhx.domain.strategy.service.rule.chain.factory.DefaultChainFactory;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;

import static cn.minhx.types.common.Constants.COLON;
import static cn.minhx.types.common.Constants.SPACE;

/**
 * 【抽奖责任链】权重范围规则
 *
 * @author min
 */
@Slf4j
@Component("rule_weight")
public class RuleWeightLogicChain extends AbstractLogicChain {

    @Resource
    private IStrategyRepository repository;
    @Resource
    private IStrategyDispatch strategyDispatch;

    public Long userCostScore = 4500L;

    /**
     * 权重规则过滤；
     * 1. 权重规则格式；4000:102,103,104,105 5000:102,103,104,105,106,107 6000:102,103,104,105,106,107,108,109
     * 2. 解析数据格式；判断哪个范围符合用户的特定抽奖范围
     *
     * @param userId     用户
     * @param strategyId 策略ID
     * @return 规则过滤结果
     */
    @Override
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    public DefaultChainFactory.StrategyAwardVO logic(String userId, Long strategyId) {
        log.info("抽奖责任链-权重范围 开始 userId:{} strategyId:{} ruleModel:{}", userId, strategyId, ruleModel());

        //  查出权重规则值
        String strategyRuleValue = repository.queryStrategyRuleValue(strategyId, ruleModel());

        //  1. 根据用户ID查询用户抽奖消耗的积分值，先写死为固定值
        long userCostScore = this.userCostScore;
        //  2. 根据权重规则值解析出对应的消耗积分数和对应的权重抽奖key
        Map<Long, String> analyticalValueGroup = getAnalyticalValue(strategyRuleValue);
        if (analyticalValueGroup.isEmpty()) {
            log.warn("抽奖责任链-权重告警【策略配置权重，但ruleValue未配置相应值】 userId: {} strategyId: {} ruleModel: {}", userId, strategyId, ruleModel());
            return next().logic(userId, strategyId);
        }
        //  3. 找出已消耗积分对应的权重抽奖key
        Long key = analyticalValueGroup.keySet().stream()
                .filter(k -> userCostScore >= k)
                .max(Comparator.naturalOrder())
                .orElse(null);
        //  至少达到第一个消耗等级，抽奖被权重规则接管
        if (key != null) {
            log.info("抽奖责任链-权重范围 接管 执行权重抽奖 userId:{} strategyId:{} userCostScore:{} ruleModel:{}", userId, strategyId, userCostScore, ruleModel());
            Long awardId = strategyDispatch.getRandomAwardId(strategyId, analyticalValueGroup.get(key));
            log.info("抽奖责任链-权重范围 接管 userId:{} strategyId:{} ruleModel:{} userCostScore:{} awardId:{}", userId, strategyId, ruleModel(), userCostScore, awardId);
            return DefaultChainFactory.StrategyAwardVO.builder().awardId(awardId).logicModel(ruleModel()).build();
        }

        // 未命中，继续执行下一个节点
        log.info("抽奖责任链-权重范围 放行 userId:{} strategyId:{} ruleModel:{}", userId, strategyId, ruleModel());
        return next().logic(userId, strategyId);
    }

    @Override
    protected String ruleModel() {
        return DefaultChainFactory.LogicModel.RULE_WEIGHT.getCode();
    }


    /**
     * 根据权重规则值解析出对应的消耗积分数和对应的权重抽奖key
     *
     * @param ruleValue 权重规则值
     * @return map<消耗积分数, 权重抽奖key>
     */
    private Map<Long, String> getAnalyticalValue(String ruleValue) {
        HashMap<Long, String> resultMap = new HashMap<>();
        String[] ruleValueGroups = ruleValue.split(SPACE);
        for (String ruleValueGroup : ruleValueGroups) {
            if (StringUtils.isBlank(ruleValueGroup)) {
                continue;
            }
            // 分割字符串以获取键和值
            String[] parts = ruleValueGroup.split(COLON);
            if (parts.length != 2) {
                throw new IllegalArgumentException("rule_weight rule_rule invalid input format" + ruleValueGroup);
            }
            resultMap.put(Long.valueOf(parts[0]), ruleValueGroup);
        }
        return resultMap;
    }

}
